

`include "cpu_defs.v"

`timescale 1ns / 1ps

module cpu(
	clk,
	rst,
	i_data,
	o_we,
	o_addr,
	o_data
);

input clk;
input rst;

input	[`CPU_DATA_WIDTH-1:0] i_data;
output o_we;
output [`CPU_ADDR_WIDTH-1:0] o_addr;
output [`CPU_DATA_WIDTH-1:0] o_data; 

wire w_cout_to_status_reg;
wire w_sign_to_status_reg;
wire w_zero_to_status_reg;
wire w_ovf_to_status_reg;
wire w_reg_file_lef_to_status_reg;
wire w_reg_file_right_to_status_reg;
wire w_q_reg_left_to_status_reg;
wire w_q_reg_right_to_status_reg;

wire [`CPU_COND_NO-1:0] w_status_reg_out;

wire w_cond_mux_out;

wire [`CPU_ADDR_WIDTH-1:0] 				w_mux_to_alu_data;

wire [`CPU_MICRO_ADDR_WIDTH-1:0] 	w_seq_to_micro_mem;
wire [`CPU_MICRO_WORD_WIDTH-1:0 ] w_micro_mem_to_pipe_reg;

wire [`CPU_MICRO_WORD_WIDTH-1:0] 	w_pipe_reg_out;

wire w_en_pl;
wire w_en_map;
wire w_en_vect;

wire [`CPU_INSTR_WIDTH-1:0] 				w_instr_reg_out;
wire [`CPU_MICRO_ADDR_WIDTH-1:0] 		w_data_to_seq;

wire [`CPU_MICRO_ADDR_A_WIDTH-1:0] 	w_mux_to_addr_a;
wire [`CPU_MICRO_ADDR_B_WIDTH-1:0] 	w_mux_to_addr_b;

wire [`CPU_MICRO_ADDR_WIDTH-1:0] w_map_prom_to_seq;

// pipe reg fileds
wire [`CPU_MICRO_FLD_INSTR_WIDTH-1:0]					w_micro_fld_instr;
wire [`CPU_MICRO_FLD_DATA_WIDTH-1:0]					w_micro_fld_data;
wire [`CPU_MICRO_FLD_CCEN_WIDTH-1:0]					w_micro_fld_ccen;
wire [`CPU_MICRO_FLD_COND_SEL_WIDTH-1:0]			w_micro_fld_cond_sel;
wire [`CPU_MICRO_FLD_CIN_WIDTH-1:0]						w_micro_fld_cin;
wire [`CPU_MICRO_FLD_ALU_FN_WIDTH-1:0]				w_micro_fld_alu_fn;
wire [`CPU_MICRO_FLD_ALU_OP_A_WIDTH-1:0]			w_micro_fld_alu_op_a;
wire [`CPU_MICRO_FLD_ALU_OP_B_WIDTH-1:0]			w_micro_fld_alu_op_b;
wire [`CPU_MICRO_FLD_ALU_DATA_WIDTH-1:0]			w_micro_fld_alu_data;
wire [`CPU_MICRO_FLD_OP_A_SEL_WIDTH-1:0]			w_micro_fld_op_a_sel;
wire [`CPU_MICRO_FLD_OP_B_SEL_WIDTH-1:0]			w_micro_fld_op_b_sel;
wire [`CPU_MICRO_FLD_ALU_DATA_SEL_WIDTH-1:0]	w_micro_fld_alu_data_sel;
wire [`CPU_MICRO_FLD_LD_INSTR_REG_WIDTH-1:0]	w_micro_fld_ld_instr_reg;
wire [`CPU_MICRO_FLD_LD_MEM_ADR_REG_WIDTH-1:0]	w_micro_fld_ld_mem_adr_reg;
wire [`CPU_MICRO_FLD_LD_MEM_WE_WIDTH-1:0]				w_cpu_micro_fld_ld_mem_we; 

// split the pipe reg into fields
assign 	{ 
					w_micro_fld_instr,
					w_micro_fld_data,
					w_micro_fld_ccen,
					w_micro_fld_cond_sel,
					w_micro_fld_cin,
					w_micro_fld_alu_fn,
					w_micro_fld_alu_op_a,
					w_micro_fld_alu_op_b,
					w_micro_fld_alu_data,
					w_micro_fld_op_a_sel,
					w_micro_fld_op_b_sel,
					w_micro_fld_alu_data_sel,
					w_micro_fld_ld_instr_reg,
					w_micro_fld_ld_mem_adr_reg,
					w_cpu_micro_fld_ld_mem_we
				} = w_pipe_reg_out;

assign o_we = w_cpu_micro_fld_ld_mem_we;

alu_top alu_top_inst(
	.clk(clk),
	.i_reg_file_left(1'b0),
	.i_reg_file_right(1'b0),
	.i_q_reg_left(1'b0),
	.i_q_reg_right(1'b0),
	.i_cin(w_micro_fld_cin),
	.i_instr(w_micro_fld_alu_fn),
	.i_a_addr(w_mux_to_addr_a),
	.i_b_addr(w_mux_to_addr_b),
	.i_data(w_mux_to_alu_data),

	.o_cout(w_cout_to_mux),
	.o_sign(w_sign_to_mux),
	.o_zero(w_zero_to_mux),
	.o_ovf(w_ovf_to_mux),
	.o_reg_file_left(w_reg_file_lef_to_mux),
	.o_reg_file_right(w_reg_file_right_to_mux),
	.o_q_reg_left(w_q_reg_left_to_mux),
	.o_q_reg_right(w_q_reg_right_to_mux),
	.o_data( o_data )
);

seq seq_inst(
	.clk(clk),
	.i_cin(1'b1),
	.i_cc(w_cond_mux_out), 
	.i_ccen(w_micro_fld_ccen),
	.i_oe(1'b1),
	.i_rld(1'b0),
	.i_data(w_data_to_seq),
	.i_instr(w_micro_fld_instr),
	
	.o_full(),
	.o_en_pl(w_en_pl),
	.o_en_map(w_en_map),
	.o_en_vect(w_en_vact),	
	.o_data( w_seq_to_micro_mem )
);

defparam pipe_reg_status_inst.DATA_WIDTH = `CPU_COND_NO;
pipe_reg pipe_reg_status_inst(
	.clk(clk),
	.rst(rst),
	.i_data( {	w_q_reg_right_to_status_reg,
	 						w_q_reg_left_to_status_reg,
	 						w_reg_file_right_to_status_reg,
	 						w_reg_file_lef_to_status_reg,
	 						w_ovf_to_status_reg,
	 						w_zero_to_status_reg,
	 						w_sign_to_status_reg,
	 						w_cout_to_status_reg } ),
	.o_data(w_status_reg_out)
);

defparam pipe_reg_micro_instr_inst.DATA_WIDTH = `CPU_MICRO_WORD_WIDTH;
pipe_reg pipe_reg_micro_instr_inst(
	.clk(clk),
	.rst(rst),
	.i_data(w_micro_mem_to_pipe_reg),
	.o_data(w_pipe_reg_out) 
);

defparam micro_mem_inst.DATA_WIDTH 	= `CPU_MICRO_WORD_WIDTH;
defparam micro_mem_inst.ADDR_WIDTH 	= `CPU_MICRO_ADDR_WIDTH;
defparam micro_mem_inst.MEM_SIZE		= `CPU_MICRO_MEM_SIZE;
micro_mem micro_mem_inst(
	.i_addr(w_seq_to_micro_mem),
	.o_data(w_micro_mem_to_pipe_reg)
);

defparam ts_buff_micro_instr_inst.DATA_WIDTH = `CPU_MICRO_ADDR_WIDTH;
ts_buff ts_buff_micro_instr_inst(
	.i_oen(w_en_pl),
	.i_data(w_micro_fld_data),
	.o_data(w_data_to_seq)
);

mux1x8 mux1x8_inst(
	.i_sel(w_micro_fld_cond_sel),
	.i_in0(w_status_reg_out[0]),
	.i_in1(w_status_reg_out[1]),
	.i_in2(w_status_reg_out[2]),
	.i_in3(w_status_reg_out[3]),
	.i_in4(w_status_reg_out[4]),
	.i_in5(w_status_reg_out[5]),
	.i_in6(w_status_reg_out[6]),
	.i_in7(w_status_reg_out[7]),

	.o_out( w_cond_mux_out )
);

defparam map_prom_inst.DATA_WIDTH = `CPU_MICRO_ADDR_WIDTH;
defparam map_prom_inst.ADDR_WIDTH = `CPU_MAP_PROM_ADDR_WIDTH;
defparam map_prom_inst.MEM_SIZE	 	= `CPU_MAP_PROM_SIZE;
micro_mem map_prom_inst(
	.i_addr(w_instr_reg_out[31:24]), // TODO : think !
	.o_data(w_map_prom_to_seq)
);

defparam ts_buff_map_rom_inst.DATA_WIDTH = `CPU_MICRO_ADDR_WIDTH;
ts_buff ts_buff_map_rom_inst(
	.i_oen(w_en_map),
	.i_data(w_map_prom_to_seq),
	.o_data(w_data_to_seq)
);

defparam instr_reg_inst.DATA_WIDTH = `CPU_DATA_WIDTH;
q_reg instr_reg_inst(
	.clk(clk),
	.i_ld_en(w_micro_fld_ld_instr_reg),
	.i_data(i_data),
	.o_data(w_instr_reg_out)
);

defparam mux_op_a_sel.DATA_WIDTH = `CPU_MICRO_FLD_ALU_OP_A_WIDTH;
mux1x2 mux_op_a_sel(
	.i_sel(w_micro_fld_op_a_sel),
	.i_data0(w_micro_fld_alu_op_a),
	.i_data1(w_instr_reg_out[9:5]), // TODO : think !
	.o_data(w_mux_to_addr_a)
);

defparam mux_op_b_sel.DATA_WIDTH = `CPU_MICRO_FLD_ALU_OP_B_WIDTH;
mux1x2 mux_op_b_sel(
	.i_sel(w_micro_fld_op_b_sel),
	.i_data0(w_micro_fld_alu_op_b),
	.i_data1(w_instr_reg_out[4:0]), // TODO : think !
	.o_data(w_mux_to_addr_b)
);

defparam mux_alu_data_sel.DATA_WIDTH = `CPU_DATA_WIDTH;
mux1x4v2 mux_alu_data_sel(
	.i_sel(w_micro_fld_alu_data_sel),
	.i_data0(w_micro_fld_alu_data),
	.i_data1({{16{1'b0}},w_instr_reg_out[15:0]}), // TODO : think !
	.i_data2(i_data),
	.i_data3({32{1'b0}}),	
	.o_data(w_mux_to_alu_data)
);

defparam mem_adr_reg_inst.DATA_WIDTH = `CPU_ADDR_WIDTH;
q_reg mem_adr_reg_inst(
	.clk(clk),
	.i_ld_en(w_micro_fld_ld_mem_adr_reg),
	.i_data(o_data),
	.o_data(o_addr)
);

endmodule
